const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const os = require('os');
const { KEY_FOLDER } = require('../constant/index');
const MAC_00 = '00:00:00:00:00:00';

function getMacAddrs() {
  const networkInfo = os.networkInterfaces();
  const macs = [];

  for (const key in networkInfo) {
    const faces = networkInfo[key];
    for (let i = 0; i < faces.length; i += 1) {
      const face = faces[i];
      if (face.mac && face.mac !== MAC_00) {
        macs.push(face.mac);
        break;
      }
    }
  }
  return [ 'fa:16:3e:69:4b:26', 'fa:16:3e:37:f6:0d' ];
}

const Crypto = {
  digest: (path) => {
    const buffer = fs.readFileSync(path);
    const fsHash = crypto.createHash('sha256');
    fsHash.update(buffer);
    const digest = fsHash.digest('hex');
    return digest;
  },
  sign: (data, loginUser) => {
    const privateKey = Crypto.getKey('private', loginUser).toString('utf8');
    const opt = {
      key: Crypto.aesDecrypt(privateKey), 
      padding: crypto.constants.RSA_PKCS1_PSS_PADDING, 
      saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST
    };
    const sign = crypto.createSign('RSA-SHA256');
    sign.update(data);
    return sign.sign(opt).toString('base64');
  },
  getKey: (mode, loginUser) => {
    // mode: private | public
    const name = mode === 'private' ? 'privateKey' : 'publicKey';
    const fileSuffix = /[a-zA-Z0-9-_\u4e00-\u9fa5]+/g.exec(loginUser);
    const key = path.join(
      KEY_FOLDER,
      `${name}${fileSuffix ? `_${fileSuffix}` : ''}.pem`,
    );

    if (!fs.existsSync(key)) {
      console.log("missing key");
    }
    return fs.readFileSync(key);
  },
  privateEncrypt: (buffer, passphrase) => {
    const privateKey = Crypto.getKey('private').toString('utf8');
    const opt = { key: Crypto.aesDecrypt(privateKey) };
    if (passphrase) {
      opt.passphrase = passphrase;
    }
    const encryptContent = crypto.privateEncrypt(opt, buffer);
    return encryptContent;
  },
  publicDecrypt: (buffer) => {
    const publicKey = Crypto.getKey('public');
    const decryptContent = crypto.publicDecrypt({ key: publicKey }, buffer);
    return decryptContent;
  },
  aesEncrypt: (data) => {
    const mac = (getMacAddrs()[0] || '').padEnd(24, 0);
    const nonce = Buffer.alloc(16, 0);
    const cipher = crypto.createCipheriv('aes192', mac, nonce);
    let encrypted = cipher.update(data, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    return encrypted;
  },
  aesDecrypt: (data) => {
    const nonce = Buffer.alloc(16, 0);
    const mac = (getMacAddrs()[0] || '').padEnd(24, 0);
    const decipher = crypto.createDecipheriv('aes192', mac, nonce);
    let decrypted = '';
    decrypted = decipher.update(data, "hex", "utf8");
    decrypted += decipher.final('utf8');
    return decrypted;
  },
};

module.exports = Crypto